package com.application.model.xml;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Scanner;

import org.apache.log4j.Logger;

import com.application.model.exceptions.LoadEntityException;
import com.application.model.exceptions.WriteEntityException;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class ConfigurationManager<T> {
	private Logger logger;

	public ConfigurationManager() {
		logger = Logger.getLogger(getClass());
	}

	/**
	 * lee el archivo y lo convierte en un objeto
	 * @param path
	 * @return
	 * @throws PMPolicyConfigurationException
	 */
	@SuppressWarnings("unchecked")
	public T load(String path,String charSet) throws LoadEntityException {
		T configuration = null;
		try {
			// writeChargingConfiguration();
			String dato = getContenido(path,charSet);
			XStream xstream = new XStream(new DomDriver(charSet));
			// xstream.processAnnotations();
			configuration = (T) xstream.fromXML(dato);
				           
		} catch (Exception e) {
			e.printStackTrace();
			throw new LoadEntityException(e);
		}
		return configuration;
	}

	

	public void write(T configuration, String path,String charSet) throws WriteEntityException {
//		ByteArrayOutputStream outputStream = null;
//		Writer writer = null;
		try {
//			FileWriter out = null;
//			XStream xstream = new XStream();
//			String salida = xstream.toXML(configuration);
//			out = new FileWriter(new File(path));
//			out.write(salida);
//			out.close();

//			XStream xstream = new XStream(new DomDriver("UTF-8"));
//			outputStream = new ByteArrayOutputStream();
//
//			writer = new OutputStreamWriter(outputStream, "UTF-8");
//
//			xstream.toXML(configuration, writer);
			
//			
			FileWriter out = null;
//			XStream xstream = new XStream(new DomDriver(charSet));
			XStream xstream = new XStream();
			out = new FileWriter(new File(path));
			xstream.toXML(configuration,out);
			out.close();

		} catch (Exception e) {
			throw new WriteEntityException(e);
		}finally{
//			try{
//			outputStream.close();
//			writer.close();
//			}catch (Exception e) {
//				// TODO: handle exception
//			}
		}
	}

	@SuppressWarnings("deprecation")
	private String getContenido(String path, String charSet) throws FileNotFoundException, IOException {
		StringBuffer contenido = new StringBuffer();
		File file = new File(path);
		if (file.exists()) {
			Scanner scanner = new Scanner(new FileInputStream(path), charSet);
		    try {
		      while (scanner.hasNextLine()){
		    	  contenido.append(scanner.nextLine());
		      }
		    }
		    finally{
		      scanner.close();
		    }
//			FileInputStream fileInputStream = new FileInputStream(path);
//			InputStreamReader input = new InputStreamReader(fileInputStream,charSet);
//			while (input.available() != 0) {
//				contenido.append(input.readLine());
//			}
//			input.close();
		}
		return contenido.toString();
	}
	
	
	/**
	 * Lee el archivo binario y lo convierte en un objeto
	 * @param path
	 * @return
	 * @throws PMPolicyConfigurationException
	 */
	@SuppressWarnings("unchecked")
	public T loadBinary(String path) throws LoadEntityException {
		T configuration = null;
		
		try {
			ObjectInputStream inputStream = null;
			inputStream = new ObjectInputStream(new FileInputStream(path));
			configuration = (T) inputStream.readObject();
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new LoadEntityException(e);
		}
		
		return configuration;
	}

	/**
	 * Se lee la configuracion: primero intenta leer el archivo temporal, de no encontrar el archivo temporal intenta leer el archivo aplicado de no
	 * encontrar el archivo aplicado lee el archivo default
	 * 
	 * @param defaultPath
	 *            path de archivo default
	 * @param tmpPath
	 *            path de archivo temporal
	 * @param applyPath
	 *            path de archivo aplicado
	 * @return devuelve el objeto que se contruyo a partir del archivo xml
	 * @throws PMPolicyConfigurationException
	 *             si no encuentra el archivo defualt
	 */
	public T loadBinary(String defaultPath, String tmpPath, String applyPath) throws LoadEntityException {
		T configuration = null;
		try {
			try {
				configuration = loadBinary(applyPath);
				logger.info("Se leyo la configuracion applied");
			} catch (LoadEntityException e) {
				try {
					// logger.warn(e, e.fillInStackTrace());
					logger.warn("No se pudo leer la configuracion applied");
					configuration = loadBinary(tmpPath);
					logger.info("Se leyo la configuracion tmp");
				} catch (Exception e1) {
					// logger.warn(e, e.fillInStackTrace());
					logger.warn("No se pudo leer la configuracion tmp");
					configuration = loadBinary(defaultPath);
					logger.info("Se leyo la configuracion Defualt");
				}
			}
		} catch (Exception e) {
			throw new LoadEntityException(e);
		}
		return configuration;
	}	
	
	/**
	 * Guarda el objeto en un archivo binario
	 * @param configuration
	 * @param path
	 * @throws PMPolicyConfigurationPersistenceException
	 */
	public void writeBinary(T configuration, String path) throws WriteEntityException {
		try {
			
			ObjectOutputStream outputStream = null;
			outputStream = new ObjectOutputStream(new FileOutputStream(path));
			outputStream.writeObject(configuration);
			outputStream.close();

		} catch (Exception e) {
			throw new WriteEntityException(e);
		}
	}	

}
